<template>
    <a-popup ref="popup" popPlacement="right-start" :popModifiers="popModifiers" v-model:popShown="state.popShown" :escToClose="false" :trigger="'hover'">
        <textarea class="a-input-textarea" :disabled="formItemHook.myDisabled" :readonly="props.readonly" :class="[
            `color-${formItemHook.myColor}`,
            `size-${formItemHook.mySize}`,
            { sharp: formItemHook.mySharp },
            { disabled: formItemHook.myDisabled },
        ]" :value="value" :placeholder="placeholder" :rows="props.rows" @input="methods.input(($event.target as any).value)"></textarea>
        <template v-slot:pop>
            <a-button :color="formItemHook.myColor" :size="formItemHook.mySize" :sharp="formItemHook.mySharp" :square="true" :link="true" @click="methods.clear">
                <span class="fa fa-fw fa-remove"></span>
            </a-button>
        </template>
    </a-popup>
</template>

<style lang="scss" scoped>
@use "sass:math";
@import "../scss/vars";

.a-input-textarea {
    box-sizing: border-box;
    outline: none;
    transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;

    &.disabled {
        opacity: 0.5;
        cursor: not-allowed;
    }

    @each $colorPackageName, $colorPackageValue in $colorPackages {
        $bgColor: map-get($colorPackageValue, "bgColor");

        &.color-#{$colorPackageName} {
            background-color: $defaultBgColor;
            border: solid 1px $bgColor;

            &:focus:not(.disabled) {
                border-color: darken($bgColor, 20%);
                box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),
                    0 0 8px lighten($bgColor, 10%);
            }
        }
    }

    @each $sizePackageName, $sizePackageValue in $sizePackages {
        &.size-#{$sizePackageName} {
            padding: math.div(map-get($sizePackageValue, "space"), 2) map-get($sizePackageValue, "space");
            font-size: map-get($sizePackageValue, "fontSize");

            &:not(.sharp) {
                border-radius: map-get($sizePackageValue, "borderRadius");
            }
        }
    }
}
</style>

<script setup lang="ts">
import APopup from './APopup.vue'
import AButton from './AButton.vue'
import utils from "@/common/utils"
import { FormItemProvided, InputPropsType, PopupExposed, Rule_maxLength, Rule_minLength } from '@/types'
import { computed, inject, onMounted, reactive, ref, watch } from 'vue'
import { useInput } from '@/hooks/useInput'
import { useFormItem } from '@/hooks/useFormItem'

interface PropsType extends InputPropsType<string | undefined, Rule_minLength | Rule_maxLength> {
    readonly?: boolean
    clearable?: boolean
    placeholder?: string
    rows?: number
}
const props = withDefaults(defineProps<PropsType>(), {
    value: undefined,
    color: undefined,
    disabled: undefined,
    size: undefined,
    sharp: undefined,
    rules: () => [],
    isInner: false,
    readonly: false,
    clearable: true,
    placeholder: undefined,
    rows: 5
})

interface StateType {
    popShown: boolean
}
const state = reactive<StateType>({
    popShown: false
})

const emit = defineEmits<{
    (e: 'update:value', value?: string): void
    (e: 'clear'): void
    (e: 'validate', result: [boolean?, string?]): Promise<void>
}>()
const inputHook = useInput(props)
const formItemHook = useFormItem(props)
const formItem = inject<FormItemProvided | undefined>('formItem', undefined)

const sizePackage = computed(() => {
    return utils.getSizePackageByName(formItemHook.value.mySize)
})
const popModifiers = computed(() => {
    return [
        {
            name: 'offset',
            options: {
                offset: [0, -sizePackage.value.size],
            }
        },
        {
            name: 'preventOverflow',
            options: {
                mainAxis: false,
                altAxis: false,
            }
        }
    ]
})
const diff = computed(() => {
    if (props.rules === undefined) {
        return undefined
    }
    let maxLengthRule = props.rules.find(a => a.name === 'maxLength') as Rule_maxLength | undefined
    if (!maxLengthRule) {
        return undefined
    }
    let valueLength = props.value?.length ?? 0
    return {
        valid: valueLength <= maxLengthRule.value,
        text: `${valueLength}/${maxLengthRule.value}`
    }
})
watch(() => inputHook.validator.valid, () => {
    if (props.isInner) {
        return
    }
    emit('validate', [inputHook.validator.valid, inputHook.validator.errorMessage])
})
watch(() => diff.value, () => {
    methods.setDiffResult()
})
onMounted(() => {
    methods.setDiffResult()
})
const popupRef = ref<PopupExposed>()
const methods = {
    input(val?: string) {
        emit('update:value', val)
    },
    getTargetEl() {
        return popupRef.value?.getTargetEl()
    },
    getPopEl() {
        return popupRef.value?.getPopEl()
    },
    clear() {
        if (!props.readonly) {
            this.input(undefined)
            this.getTargetEl()?.focus()
        }
        emit('clear')
    },
    setDiffResult() {
        formItem?.value.setDiffResult(diff.value?.valid, diff.value?.text)
    },
}
</script>